using System;
using System.Collections.Generic;

namespace UMC.Data
{
    public class Set<T> : IDisposable
    {
        public int Tag { get; set; }
        public Span<T> Span => tuples.AsSpan(0, _size);
        public void Clear()
        {
            _size = 0;
        }

        public Set(IComparer<T> comparer)
        {
            this.comparer = comparer;
            this.tuples = System.Buffers.ArrayPool<T>.Shared.Rent(10);
        }
        public Set(Comparison<T> comparer)
        {
            this.comparer = Comparer<T>.Create(comparer);
            this.tuples = System.Buffers.ArrayPool<T>.Shared.Rent(10);
        }
        public Set(int capacity, IComparer<T> comparer)
        {
            this.comparer = comparer;
            this.tuples = System.Buffers.ArrayPool<T>.Shared.Rent(capacity);
        }
        public T this[int i]
        {
            get { return tuples[i]; }
        }
        public int Count => _size;
        private IComparer<T> comparer;
        private T[] tuples;//= new T[10];
        int _size;
        public bool Contains(T name)
        {
            return Utility.Search(tuples, 0, _size, name, comparer) > -1;
        }
        public int IndexOf(T name)
        {
            return Utility.Search(tuples, 0, _size, name, comparer);// > -1;
        }

        public void Remove(T value)
        {
            int index = Utility.Search(tuples, 0, _size, value, comparer);
            if (index > -1)
            {
                Array.Copy(tuples, index + 1, tuples, index, _size - index - 1);
                _size--;
            }
        }
        public void Put(T value)
        {

            int index = Utility.Search(tuples, 0, _size, value, comparer);
            if (index > -1)
            {
                tuples[index] = value;
                return;
            }
            else
            {

                if (_size == tuples.Length)
                {
                    T[] b = System.Buffers.ArrayPool<T>.Shared.Rent(_size + 10);
                    Array.Copy(tuples, 0, b, 0, _size);
                    System.Buffers.ArrayPool<T>.Shared.Return(this.tuples);
                    tuples = b;
                }
                index = ~index;
                Array.Copy(tuples, index, tuples, index + 1, _size - index);
                tuples[index] = value;
                _size++;
            }

        }
        public bool TryGetValue(T value, out T result)
        {
            result = default;
            int index = Utility.Search(tuples, 0, _size, value, comparer);
            if (index > -1)
            {
                result = tuples[index];//.Item2;
                return true;
            }
            return false; ;
        }
        public bool TryGetValue<V>(V value, out T result, CompareTo<T, V> comparer)
        {
            result = default;
            int index = Utility.Search(tuples, 0, _size, value, comparer);
            if (index > -1)
            {
                result = tuples[index];//.Item2;
                return true;
            }
            return false; ;
        }

        bool disposing = false;
        public void Dispose()
        {
            if (disposing == false)
            {
                System.Buffers.ArrayPool<T>.Shared.Return(this.tuples);
                disposing = true;
            }
        }
    }
    public class Set<T, V> : IDisposable
    {
        public int Tag { get; set; }
        public Set(int capacity, CompareTo<T> comparer)
        {
            this.compareTo = comparer;
            this.tuples = System.Buffers.ArrayPool<Tuple<T, V>>.Shared.Rent(capacity);
        }

        Tuple<T, V>[] tuples;// = new Tuple<T, V>[10];
        int _size;
        CompareTo<T> compareTo;
        public Set(CompareTo<T> comparer)
        {
            this.compareTo = comparer;

            this.tuples = System.Buffers.ArrayPool<Tuple<T, V>>.Shared.Rent(10);

        }
        public void Remove(T name)
        {
            int index = Utility.Search(tuples, 0, _size, name, (x, y) => compareTo(x.Item1, y));
            if (index > -1)
            {
                Array.Copy(tuples, index + 1, tuples, index, _size - index - 1);
                _size--;
            }
        }
        public void Clear()
        {
            _size = 0;
        }

        public bool TryGetValue(T name, out V result)
        {
            result = default;
            int index = Utility.Search(tuples, 0, _size, name, (x, y) => compareTo(x.Item1, y));
            if (index > -1)
            {
                result = tuples[index].Item2;//.Item2;
                return true;
            }
            return false; ;
        }
        public int Count => _size;
        public ReadOnlySpan<Tuple<T, V>> Span => tuples.AsSpan(0, _size);

        public ReadOnlySpan<V> Values
        {
            get
            {
                var values = new V[_size];
                for (var i = 0; i < _size; i++)
                {
                    values[i] = tuples[i].Item2;
                }
                return values;

            }
        } //tuples.AsSpan(0, _size);
        public bool Contains(T name)
        {
            return Utility.Search(tuples, 0, _size, name, (x, y) => compareTo(x.Item1, y)) > -1;
        }

        bool disposing = false;
        public void Dispose()
        {
            if (disposing == false)
            {
                System.Buffers.ArrayPool<Tuple<T, V>>.Shared.Return(this.tuples);
                disposing = true;
            }
        }
        public V this[T name]
        {
            get
            {
                int index = Utility.Search(tuples, 0, _size, name, (x, y) => compareTo(x.Item1, y));
                if (index > -1)
                {
                    return tuples[index].Item2;
                }
                return default;
            }
            set
            {
                int index = Utility.Search(tuples, 0, _size, name, (x, y) => compareTo(x.Item1, y));
                if (index > -1)
                {
                    tuples[index] = Tuple.Create(name, value);
                    return;
                }
                if (_size == tuples.Length)
                {
                    Tuple<T, V>[] b = System.Buffers.ArrayPool<Tuple<T, V>>.Shared.Rent(_size + 10);
                    Array.Copy(tuples, 0, b, 0, _size);
                    System.Buffers.ArrayPool<Tuple<T, V>>.Shared.Return(tuples);
                    tuples = b;
                }
                index = ~index;
                Array.Copy(tuples, index, tuples, index + 1, _size - index);
                tuples[index] = Tuple.Create(name, value);
                _size++;
            }
        }
    }
}